package com.darsystems.foghourz.client;


import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;

public class FBLoginPanel extends DecoratorPanel {

	
	private final PasswordTextBox passwordTextBox = new PasswordTextBox();
	private final TextBox fbUrlTextBox = new TextBox();
	private String lastFbUrl;
	
	private final TextBox fbUserTextBox = new TextBox();
	private final Button loginButton = new Button("Login");
	private LoginHandler loginHandler;
	private StatusDisplay statusDisplay;
	
	private static final String USER_COOKIE_NAME = "fogBugzUserToken";
	private final FogBugzServiceAsync fogbugzService = GWT
			.create(FogBugzService.class);

	private String token;
	
	public String getToken()
	{
		return token;
	}
	
	public FBLoginPanel(StatusDisplay statusPanel, LoginHandler loginHandler)
	{
		this.loginHandler = loginHandler;
		this.statusDisplay = statusPanel;
		
		buildUI();

		fbUserTextBox.setText(Cookies.getCookie(USER_COOKIE_NAME));
		
		showPasswordEntry(false);
	}
	
	
	
	public void reopen()
	{
		if(fbUrlTextBox.getText().length() == 0)
		{
			getUsersFBServerURL();
		}
		else
		{
			allowLogin(false);
		}
	}
	
	private void buildUI()
	{
		FlexTable layout = new FlexTable();
			
		setupHandlers();
		final String width = "15em";
		fbUrlTextBox.setWidth(width);
		fbUserTextBox.setWidth(width);
		passwordTextBox.setWidth(width);
		
		FlexCellFormatter cellFormatter = layout.getFlexCellFormatter();

	    // Add a title to the form
	    layout.setHTML(0, 0, "Fogbuz Server Information");
	    cellFormatter.setColSpan(0, 0, 2);
	    cellFormatter.setHorizontalAlignment(0, 0,
	        HasHorizontalAlignment.ALIGN_CENTER);
		
		layout.setText(1, 0, "Server:");
		layout.setWidget(1, 1, fbUrlTextBox);
		
		layout.setText(2, 0, "User:");
		layout.setWidget(2, 1, fbUserTextBox);
		
		layout.setText(3, 0, "Password:");
		layout.setWidget(3, 1, passwordTextBox);
		
		layout.setWidget(4, 1, loginButton);
		this.setWidget(layout);
	}

	private boolean isFBUrlDirty()
	{
		return fbUrlTextBox.getText().length() == 0 || fbUrlTextBox.getText().compareTo(lastFbUrl) != 0;
	}
	
	private void setupHandlers() {
		
		/*fbUrlTextBox.addKeyPressHandler(new KeyPressHandler() {
	      public void onKeyPress(KeyPressEvent event) {
	    	  isFBUrlDirty = true;
	        }
	      });*/
		
		final KeyPressHandler onEnter = new KeyPressHandler() {
		      public void onKeyPress(KeyPressEvent event) {
		    	  if (event.getCharCode() == KeyCodes.KEY_ENTER) {
		        	  getNewToken();
		          }
		        }
			  };
		        
		fbUserTextBox.addKeyPressHandler(onEnter);
		passwordTextBox.addKeyPressHandler(onEnter);
		
		loginButton.addClickHandler(new ClickHandler()
		{
			public void onClick(ClickEvent event) {
	        	getNewToken();
			}
		});
	}
	
	private void showPasswordEntry(boolean show) {
		this.setVisible(show);
	}
	
	private void allowLogin(boolean again)
	{
		showPasswordEntry(true);
		statusDisplay.loginMessage(again);
		passwordTextBox.setFocus(true);
	}
	
	/**
	 * Starting point for logging in to the fog bugz server
	 */
	public void getLoggedOnToFB() {	
		final FBAuthorizer fbAuthorizer = new FBAuthorizer();
		fbAuthorizer.checkLoginStatus(new AuthorizeCallback(){
			public void onFailure(Throwable caught) {
				statusDisplay.problem("SERVER ERROR" + caught.getMessage());
				
			}
			public void onLoggedIn(String logoutUrl) {
				setToken(fbAuthorizer.getToken());
				loginHandler.loginSucceeded();
				
			}
			public void onNotLoggedIn(String loginUrl) {
				getUsersFBServerURL();
			}
			
		});
	}

	private void setToken(String newToken)
	{
		token = newToken;
		
		Cookies.setCookie(FBAuthorizer.TOKEN_COOKIE_NAME, token);
		Cookies.setCookie(USER_COOKIE_NAME, fbUserTextBox.getText());
	}
	
	private void getNewToken()
	{
		if(isFBUrlDirty())
		{
			setFBUrlAndGetToken(fbUrlTextBox.getText());
		}
		else
		{
			getNewTokenAsync();
		}
	
	}
	private void getNewTokenAsync()
	{
		final String userName = fbUserTextBox.getText();
		final String password = passwordTextBox.getText();
		
		fogbugzService.login(userName, password, new AsyncCallback<String>(){
			public void onFailure(Throwable caught) {
				// Show the RPC error message to the user
				statusDisplay.problem("SERVER ERROR: " + caught.getMessage());
			}

			public void onSuccess(String result) {
				if(result.isEmpty())
				{
					allowLogin(true);
				}
				else
				{
					setToken(result);
					loginHandler.loginSucceeded();
				}
			}
		});
		
		showPasswordEntry(false);
		statusDisplay.setCommMessage("Getting new token...");
	}
	
	
	
	/*
	 * If the stored token cookie fails (of the cookie did not exist) then go get the user's FB server information.
	 * This is async so this just starts the get and calls the next step - which is to allow logging in. 
	 */
	private void getUsersFBServerURL()
	{
		FBConfigServiceAsync service = GWT.create(FBConfigService.class);
	    service.getUserFBServer(new AsyncCallback<String>() {
	      public void onFailure(Throwable error) {
	    	  
	      }

	      public void onSuccess(String result) {
	    	  setFbUrlDisplay(result);
	    	  allowLogin(false);
	      }
	    });
	}
	
	private void setFBUrlAndGetToken(String fbServerUrl)
	{
		FBConfigServiceAsync service = GWT.create(FBConfigService.class);
		service.setUserFBServer(fbServerUrl, new AsyncCallback<String>() {
		      public void onFailure(Throwable error) {
		    	  
		      }

		      public void onSuccess(String result) {
		    	  setFbUrlDisplay(result);
		    	  getNewTokenAsync();
		      }
		    });
	}
	
	private void setFbUrlDisplay(String result) {
		fbUrlTextBox.setText(result);
    	this.lastFbUrl = result;
	}

}
